package com.seleniti.enpareja.android.control.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.ioc.commons.flowcontrol.messageboxfactory.MessageBoxFactory;
import org.ioc.commons.utils.Format;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.text.Editable;
import android.text.InputType;
import android.widget.EditText;
import android.widget.Toast;

public class MessageBoxFactoryImpl implements MessageBoxFactory {
	private static final String CAPTION = "caption";
	private static final String MESSAGE = "message";
	private static final String INITIAL_VALUE = "initial_value";
	private static final String RESPONSE_KEY = "response_key";

	public static class MessageBoxFactoryConfirmDialogFragment extends android.support.v4.app.DialogFragment {
		private static Map<String, ConfirmResponse> responses = new HashMap<String, ConfirmResponse>();

		public MessageBoxFactoryConfirmDialogFragment() {
		}

		public android.app.Dialog onCreateDialog(android.os.Bundle b) {
			Bundle args = this.getArguments();

			String caption = args.getString(CAPTION);
			String message = args.getString(MESSAGE);
			final String responseKey = args.getString(RESPONSE_KEY);

			final ConfirmResponse realResponse = responses.get(responseKey);
			ConfirmResponse confirmResponse = new ConfirmResponse() {

				@Override
				public void onUserResponse(boolean userResponse) {
					responses.remove(responseKey);
					realResponse.onUserResponse(userResponse);
				}
			};
			Builder dialog = createConfirmDialog(caption, message, confirmResponse, getActivity());
			return dialog.create();
		}	}

	public static class MessageBoxFactoryErrorDialogFragment extends android.support.v4.app.DialogFragment {

		public MessageBoxFactoryErrorDialogFragment() {
		}

		public android.app.Dialog onCreateDialog(android.os.Bundle b) {
			Bundle args = this.getArguments();

			String caption = args.getString(CAPTION);
			String message = args.getString(MESSAGE);

			Builder dialog = createErrorDialog(caption, message, getActivity());
			return dialog.create();
		}
	}

	public static class MessageBoxFactoryAlertDialogFragment extends android.support.v4.app.DialogFragment {

		public MessageBoxFactoryAlertDialogFragment() {
		}

		public android.app.Dialog onCreateDialog(android.os.Bundle b) {
			Bundle args = this.getArguments();

			String caption = args.getString(CAPTION);
			String message = args.getString(MESSAGE);

			Builder dialog = createAlertDialog(caption, message, getActivity());
			return dialog.create();
		}
	}

	public static class MessageBoxFactoryPromptDialogFragment extends android.support.v4.app.DialogFragment {

		private static Map<String, PromptResponse> responses = new HashMap<String, PromptResponse>();

		public MessageBoxFactoryPromptDialogFragment() {
		}

		public android.app.Dialog onCreateDialog(android.os.Bundle b) {
			Bundle args = this.getArguments();

			String caption = args.getString(CAPTION);
			String message = args.getString(MESSAGE);
			String fInitialValue = args.getString(INITIAL_VALUE);
			final String responseKey = args.getString(RESPONSE_KEY);

			final PromptResponse realResponse = responses.get(responseKey);
			PromptResponse promptResponse = new PromptResponse() {

				@Override
				public void onUserResponse(boolean userResponse, String response) {
					responses.remove(responseKey);
					realResponse.onUserResponse(userResponse, response);
				}
			};
			Builder dialog = createPromptDialog(caption, message, fInitialValue, promptResponse, getActivity());
			return dialog.create();
		}
	}

	private final class RunnableToast implements Runnable {
		private final Object[] messageParams;
		private final String message;

		private RunnableToast(String message, Object... messageParams) {
			this.messageParams = messageParams;
			this.message = message;
		}

		@Override
		public void run() {
			Toast.makeText(context, Format.substitute(message, messageParams), Toast.LENGTH_LONG).show();
		}
	}

	private final Context context;

	public MessageBoxFactoryImpl(Context context) {
		this.context = context;
	}

	@Override
	public void info(final String caption, final String message, final Object... messageParams) {
		// Runnable runnableDialog = new Runnable() {
		//
		// @Override
		// public void run() {
		// Context context = getContext();
		//
		// new AlertDialog.Builder(context).setTitle(caption)
		// .setMessage(Format.substitute(message, messageParams))
		// .setPositiveButton(android.R.string.yes, new
		// DialogInterface.OnClickListener() {
		//
		// @Override
		// public void onClick(DialogInterface dialog, int which) {
		// dialog.dismiss();
		// }
		// }).setIcon(android.R.drawable.ic_dialog_info).show();
		// }
		// };
		//
		// tryToShow(runnableDialog, message, messageParams);
		Toast.makeText(context, Format.substitute(message, messageParams), Toast.LENGTH_LONG).show();
	}

	@Override
	public void alert(final String caption, final String message, final Object... messageParams) {
		if (context instanceof FragmentActivity) {
			MessageBoxFactoryAlertDialogFragment d = new MessageBoxFactoryAlertDialogFragment();
			Bundle b = new Bundle();
			b.putString(CAPTION, caption);
			b.putString(MESSAGE, Format.substitute(message, messageParams));
			d.setArguments(b);			
			FragmentActivity fa = (FragmentActivity) context;
			Fragment f = getVisibleFragment(fa);
			String tag = f != null ? f.getTag() : null;
			d.show(fa.getSupportFragmentManager(), tag);

		} else {
			Runnable runnableDialog = new Runnable() {

				@Override
				public void run() {
					Builder dialog = createAlertDialog(caption, Format.substitute(message, messageParams), context);
					dialog.show();
				}
			};

			tryToShow(runnableDialog, message, messageParams);
		}
	}

	@Override
	public void error(final String caption, final String message, final Object... messageParams) {
		if (context instanceof FragmentActivity) {
			MessageBoxFactoryErrorDialogFragment d = new MessageBoxFactoryErrorDialogFragment();
			Bundle b = new Bundle();
			b.putString(CAPTION, caption);
			b.putString(MESSAGE, Format.substitute(message, messageParams));
			d.setArguments(b);
			FragmentActivity fa = (FragmentActivity) context;
			Fragment f = getVisibleFragment(fa);
			String tag = f != null ? f.getTag() : null;
			d.show(fa.getSupportFragmentManager(), tag);

		} else {
			Runnable runnableDialog = new Runnable() {

				@Override
				public void run() {
					Builder dialog = createErrorDialog(caption, Format.substitute(message, messageParams), context);
					dialog.show();
				}
			};

			tryToShow(runnableDialog, message, messageParams);
		}
	}

	@Override
	public void confirm(final String caption, final String message, final ConfirmResponse confirmResponse,
			final Object... messageParams) {
		if (context instanceof FragmentActivity) {
			MessageBoxFactoryConfirmDialogFragment d = new MessageBoxFactoryConfirmDialogFragment();
			Bundle b = new Bundle();
			b.putString(CAPTION, caption);
			b.putString(MESSAGE, Format.substitute(message, messageParams));
			String responseKey = UUID.randomUUID().toString();
			MessageBoxFactoryConfirmDialogFragment.responses.put(responseKey, confirmResponse);
			b.putString(RESPONSE_KEY, responseKey);
			d.setArguments(b);			
			FragmentActivity fa = (FragmentActivity) context;
			Fragment f = getVisibleFragment(fa);
			String tag = f != null ? f.getTag() : null;
			d.show(fa.getSupportFragmentManager(), tag);
		} else {
			Builder dialog = createConfirmDialog(caption, Format.substitute(message, messageParams), confirmResponse,
					context);
			dialog.show();
		}
	}

	@Override
	public void prompt(final String caption, final String message, String initialValue,
			final PromptResponse promptResponse, final Object... messageParams) {
		final String fInitialValue = (initialValue == null) ? "" : initialValue;

		if (context instanceof FragmentActivity) {
			MessageBoxFactoryPromptDialogFragment d = new MessageBoxFactoryPromptDialogFragment();
			Bundle b = new Bundle();
			b.putString(CAPTION, caption);
			b.putString(MESSAGE, Format.substitute(message, messageParams));
			b.putString(INITIAL_VALUE, initialValue);
			String responseKey = UUID.randomUUID().toString();
			MessageBoxFactoryPromptDialogFragment.responses.put(responseKey, promptResponse);
			b.putString(RESPONSE_KEY, responseKey);
			d.setArguments(b);			
			FragmentActivity fa = (FragmentActivity) context;
//			fa.getSupportFragmentManager().beginTransaction().add(d, null).commitAllowingStateLoss();
			Fragment f = getVisibleFragment(fa);
			String tag = f != null ? f.getTag() : null;
			d.show(fa.getSupportFragmentManager(), tag);
		} else {

			Builder dialog = createPromptDialog(caption, Format.substitute(message, messageParams), fInitialValue,
					promptResponse, context);
			dialog.show();
		}
	}

	private void tryToShow(Runnable runnableDialog, final String message, final Object... messageParams) {
		Runnable runnableToast = new RunnableToast(message, messageParams);

		if (context instanceof Activity) {
			((Activity) context).runOnUiThread(runnableDialog);
		} else {
			new Handler(Looper.getMainLooper()).post(runnableToast);
		}
	}

	protected static Builder createErrorDialog(final String caption, final String message, Context context) {
		Builder dialog = new AlertDialog.Builder(context).setTitle(caption).setMessage(message)
				.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {

					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				}).setIcon(android.R.drawable.ic_dialog_alert);
		return dialog;
	}

	protected static Builder createAlertDialog(final String caption, final String message, Context context) {
		Builder dialog = new AlertDialog.Builder(context).setTitle(caption).setMessage(message)
				.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {

					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				}).setIcon(android.R.drawable.ic_dialog_alert);
		return dialog;
	}

	protected static Builder createPromptDialog(String caption, String message, String initialValue,
			final PromptResponse promptResponse, Context context) {
		final EditText input = new EditText(context);
		input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
		input.setText(initialValue);
		input.setMaxLines(1);

		Builder dialog = new AlertDialog.Builder(context).setTitle(caption).setMessage(message).setView(input)
				.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int whichButton) {
						Editable value = input.getText();
						promptResponse.onUserResponse(true, value.toString());
						dialog.dismiss();
					}
				}).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int whichButton) {
						Editable value = input.getText();
						promptResponse.onUserResponse(false, value.toString());
						dialog.dismiss();
					}
				});
		return dialog;
	}

	protected static Builder createConfirmDialog(String caption, String message, final ConfirmResponse confirmResponse,
			Context context) {
		Builder dialog = new AlertDialog.Builder(context).setTitle(caption).setMessage(message)
				.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {

					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
						confirmResponse.onUserResponse(true);
					}
				}).setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {

					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
						confirmResponse.onUserResponse(false);
					}
				}).setIcon(android.R.drawable.ic_dialog_alert);
		return dialog;
	}

	private Fragment getVisibleFragment(FragmentActivity fa) {
		List<Fragment> fragments = fa.getSupportFragmentManager().getFragments();
		if (fragments != null) {
			for (int i = fragments.size() - 1; i >= 0; i--) {
				Fragment f = fragments.get(i);
				if (f != null && f.getUserVisibleHint()) {
					return f;
				}
			}
		}

		return null;
	}
}
